package com.ca.project.Server.Modules.UserInfo.Service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ca.project.Redis.Constants.RedisConstants;
import com.ca.project.Server.Modules.UserInfo.Context.FindUserInfoContext;
import com.ca.project.Server.Modules.UserInfo.Context.UserInfoUpdateContext;
import com.ca.project.Server.Modules.UserInfo.Entity.UserInfo;
import com.ca.project.Server.Modules.UserInfo.Mapper.UserInfoMapper;
import com.ca.project.Server.Modules.UserInfo.Service.UserInfoService;
import com.ca.project.core.Exception.BusinessException;
import com.ca.project.core.Util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.Objects;

/**
 * @author ASUS
 * @description 针对表【user_info】的数据库操作Service实现
 * @createDate 2023-08-28 17:10:43
 */

@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 用户填写个人信息
     * <p>
     * 2.进行判断
     * 3。进行更新
     * <p>
     * 技术难点：
     * 1.确保每个学号只能拥有唯一的openid，保证唯一性
     * 2.对学号进行判断
     * 1）要比20级要大
     * 2）不能有重复学号
     * 3）学号不能乱打
     *
     * @param userInfoUpdateContext
     */
    @Override
    public void updateInfo(UserInfoUpdateContext userInfoUpdateContext) {
        doFindOpenid(userInfoUpdateContext);
        doJudgment(userInfoUpdateContext);
        doUpdate(userInfoUpdateContext);
    }

    /**
     * 根据学号查找用户信息是否存在
     *
     * @param stuNum
     * @return
     */
    @Override
    public UserInfo getUserInfo(String stuNum) {
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("stunum", stuNum);
        return getOne(wrapper);
    }

    /**
     * 找用户是否是维修人员
     *
     * @param openid
     * @return
     */
    @Override
    public Integer getRepairId(String openid) {
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("openid", openid);
        UserInfo entity = getOne(wrapper);
        return entity.getRepairId();
    }

    /**
     * 通过openid获取用户信息
     *
     * @param rOpenid
     * @return
     */
    @Override
    public UserInfo getInfo(String rOpenid) {
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("openid", rOpenid);
        return getOne(wrapper);
    }

    /**
     * 查找某用户的信息
     *
     * @param token
     * @return
     */
    @Override
    public UserInfo find(String token) {
        Object userId = JwtUtil.analyzeToken(token, RedisConstants.LOGIN_USER_ID);
        if (userId == null)
            throw new BusinessException("token解析失败");
        String key = RedisConstants.LOGIN_USER_ID + userId;
        Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);
        if (userMap == null || userMap.isEmpty())
            throw new BusinessException("token已过期,请重新登录");
        Object openid = userMap.get("openid");
        if (openid == null)
            throw new BusinessException("openid不存在");
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("openid", openid);
        return getOne(wrapper);
    }

    /**
     * 查找用户的联系方式
     *
     * @param openid
     * @return
     */
    @Override
    public String getPhone(String openid) {
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("openid", openid);
        UserInfo entity = getOne(wrapper);
        if (Objects.isNull(entity))
            throw new BusinessException("该用户不存在");
        return entity.getPhone();
    }

    /********************************************private**************************************************************/
    /**
     * 进行判断
     * 1.判断学号是否为空 、长度是否为20位
     * 2.对学号进行截取，判断学号前两位是否大于20
     * 1）做这个判断是因为当前学号最小值是20
     * 2）然后防止有人输入123等非法学号
     * 3.查询数据库做判断，看该学号是否存在
     *
     * @param userInfoUpdateContext
     */
    private void doJudgment(UserInfoUpdateContext userInfoUpdateContext) {
        String stunum = userInfoUpdateContext.getStunum();
        if (Objects.isNull(stunum) || stunum.length() < 10)
            throw new BusinessException("学号不能为空");

        int firstTwoDigits = Integer.parseInt(stunum.substring(0, 2));
        if (firstTwoDigits >= 20) {
            UserInfo entity = getUserStuNum(stunum);
            if (entity != null)
                throw new BusinessException("学号已存在，请重新输入");
        } else {
            throw new BusinessException("此为非法学号，请重新输入学号");
        }
    }

    /**
     * 修改个人信息
     *
     * @param userInfoUpdateContext
     */
    private void doUpdate(UserInfoUpdateContext userInfoUpdateContext) {
        LambdaUpdateWrapper<UserInfo> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(UserInfo::getOpenid, userInfoUpdateContext.getOpenid())
                .set(UserInfo::getRealname, userInfoUpdateContext.getRealname())
                .set(UserInfo::getDormmun, userInfoUpdateContext.getDormnum())
                .set(UserInfo::getPhone, userInfoUpdateContext.getPhone())
                .set(UserInfo::getStunum, userInfoUpdateContext.getStunum());
        int row = baseMapper.update(null, wrapper);
        if (row <= 0)
            throw new BusinessException("用户个人信息更新失败");
    }

    /**
     * 通过学号获取数据库里面的用户个人信息
     *
     * @param stunum
     * @return
     */
    private UserInfo getUserStuNum(String stunum) {
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("stunum", stunum);
        return getOne(wrapper);
    }

    /**
     * 找openid
     *
     * @param userInfoUpdateContext
     */
    private void doFindOpenid(UserInfoUpdateContext userInfoUpdateContext) {
        UserInfo entity = find(userInfoUpdateContext.getToken());
        if (Objects.isNull(entity))
            throw new BusinessException("该用户未注册");
        userInfoUpdateContext.setOpenid(entity.getOpenid());
    }
}
